<template>
  <div class="h-full">
    <div class="h-9 bg-white">
      <a-button
        class="float-right mr-2"
        :preIcon="isEditing ? ICON.SAVE : ICON.EDIT"
        :loading="loading"
        @click="handleSaveEdit"
      >
        {{ isEditing ? '保存' : '编辑' }}
      </a-button>
      <a-button
        class="float-right mr-2"
        :preIcon="ICON.PLUS"
        v-show="isEditing"
        @click="openDrawer(true, 'parameter')"
      >
        添加部件
      </a-button>
    </div>
    <GridLayout
      v-if="layout.length !== 0"
      v-model:layout="layout"
      :col-num="layoutWidth"
      :row-height="1"
      :is-draggable="draggable"
      :is-resizable="draggable"
    >
      <GridItem
        v-for="item in layout"
        :key="item.i"
        :x="item.x"
        :y="item.y"
        :w="item.w"
        :h="item.h"
        :i="item.i"
        @resize="handleResize"
        class="relative"
      >
        <button
          class="absolute top-2 right-2 z-10"
          @click="handleRemoveItem(item.i)"
          v-show="isEditing"
        >
          <CloseCircleOutlined />
        </button>
        <button
          class="absolute top-2 right-8 z-10"
          @click="handleEditForm(item)"
          v-show="isEditing"
        >
          <EditOutlined />
        </button>

        <component
          :is="tabs[switchType(item.widget.type)]"
          :dashboard="true"
          :isResize="isResize"
          :widgetData="item.widget.config[item.i].widgetData"
          :formData="item.widget.config[item.i].formData"
          :isEditing="isEditing"
          @success="handleComSuccess"
        />
      </GridItem>
    </GridLayout>
    <div
      class="text-4xl font-bold text-center mt-[10%]"
      style="height: calc(100% - 2.25rem)"
      v-else
    >
      <div> 请添加部件 </div>
    </div>
    <WidgetsDrawer @register="registerDrawer" @add="handleAddWidgets" />
    <PublicSettingModal
      :fqn="fqn"
      whereForm="dashboard"
      :randomId="randomId"
      @register="registerModal"
      @success="handleSuccess"
    />
  </div>
</template>
<script lang="ts" setup>
  import { nextTick, onMounted, reactive, ref, watch } from 'vue';
  import { GridLayout, GridItem } from 'grid-layout-plus';
  import { ICON } from '/@/enums/iconEnum';
  import WidgetsDrawer from './components/WidgetsDrawer.vue';
  import { useDrawer } from '/@/components/Drawer';
  import { CloseCircleOutlined, EditOutlined } from '@ant-design/icons-vue';
  import { generate, gridItem } from './index.data';
  import { useWebsocketStoreWithOut } from '/@/store/modules/thingsboard/websocket';
  import {
    tabs,
    switchType,
  } from '/@/views/thingsborad/resources/widgets/components/widgetsTable/components/EditorWidgets/index.data';
  import { apiDashboard, addDashboard } from '/@/api/thingsborad/dashboards/dashboard';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useRoute } from 'vue-router';
  import PublicSettingModal from './components/PublicSettingModal.vue';
  import { useModal } from '/@/components/Modal';
  import { getWidgetData } from './components/webSocket/send';
  import { getWidgetByFqn } from '/@/api/thingsborad/resources/widgets/widgets';
  import { useSystemStatusStoreWithOut } from '/@/store/modules/thingsboard/systemStatus';
  //接收路由传递的参数
  const route = useRoute();
  const fqn = ref<string>('');
  const randomId = ref<string>('');
  const isResize = ref<boolean>(false);
  // 仪表盘初始数据
  const params = reactive<any>({
    id: {},
    createdTime: 0,
    tenantId: {},
    title: '',
    image: '',
    assignedCustomers: [],
    mobileHide: false,
    mobileOrder: 1,
    configuration: {},
    externalId: null,
    name: '',
  });

  let layout = reactive<Array<gridItem>>([]);
  const isEditing = ref<boolean>(false);
  const loading = ref<boolean>(false);
  const draggable = ref<boolean>(false);
  const deleteIds = ref<Array<string>>([]);
  const layoutWidth = ref<number>(document.documentElement.clientWidth - 48);
  const { createMessage } = useMessage();
  const [registerModal, { openModal }] = useModal();
  const [registerDrawer, { openDrawer }] = useDrawer();
  const ws = useWebsocketStoreWithOut();
  const useStore = useSystemStatusStoreWithOut();

  watch(
    () => isEditing.value,
    (newVal) => {
      if (newVal) {
        // 已改变
        useStore.setIsDataChanged(true);
      } else {
        // 未改变
        useStore.setIsDataChanged(false);
      }
    },
    {
      immediate: false,
      deep: true,
    },
  );

  // 首次添加部件并打开弹窗
  const handleAddWidgets = async (item: Recordable) => {
    const randomIdFalg = generate(20);
    randomId.value = randomIdFalg;
    fqn.value = switchType(item.widgetType);
    layout.push({
      x: 200,
      y: 40,
      w: 200,
      h: 20,
      i: randomIdFalg,
      widget: {
        config: {
          [randomIdFalg]: {
            formData: null, //部件表单数据 接口数据
            widgetData: null, //部件渲染数据
          },
        },
        type: item.widgetType,
        x: 200,
        y: 40,
        w: 200,
        h: 20,
      },
    });
    // 首次打开弹窗表单
    const { descriptor } = await getWidgetByFqn({ fqn: 'tenant.' + item.fqn });
    nextTick(() => {
      // 部件配置好的表单数据，不为空
      openModal(true, {
        whereFrom: 'dashboard',
        formData: JSON.parse(descriptor.defaultConfig),
      });
    });
  };

  // 打开编辑弹窗
  const handleEditForm = (item: Recordable) => {
    fqn.value = switchType(item.widget.type);
    randomId.value = item.i;
    nextTick(() => {
      openModal(true, { whereFrom: 'dashboard', formData: item.widget.config[item.i].formData });
    });
  };
  // 弹窗编辑完成后请求渲染数据
  const handleSuccess = async (randomId: string, formData: Recordable) => {
    let type = '';
    layout.forEach((item) => {
      if (item.i === randomId) {
        item.widget.config[randomId].formData = formData;
        type = item.widget.type;
      }
    });
    // 发送请求webSocket
    const widgetData = await getWidgetData(ws.getAndIncrementCmdId(), type, formData);

    layout.forEach((item) => {
      if (item.i == randomId) {
        item.widget.config[randomId].widgetData = widgetData;
      }
    });
  };

  function handleComSuccess() {}
  // 删除layout中对应id的部件
  const handleRemoveItem = (id: string) => {
    const index = layout.findIndex((item) => item.i === id);
    deleteIds.value.push(id);
    if (index > -1) {
      layout.splice(index, 1);
    }
  };
  // 调整块的大小位置
  const handleResize = (
    i: string | number,
    newH: number,
    newW: number,
    newHPx: number,
    newWPx: number,
  ) => {
    console.log(newH, newW, newHPx, newWPx);
    isResize.value = !isResize.value;
    layout.forEach((item) => {
      if (item.i == i) {
        item.widget.h = newH;
        item.widget.w = newW;
        item.widget.x = newWPx;
        item.widget.y = newHPx;
      }
    });
  };

  // 点击保存
  const handleSaveEdit = () => {
    isEditing.value = !isEditing.value;
    isEditing.value ? (loading.value = false) : (loading.value = true);
    draggable.value = !draggable.value;
    if (isEditing.value) return;
    // 保存逻辑
    const paramsItems = Object.keys(params.configuration.widgets);
    const layoutItems: string[] = [];
    layout.forEach((item) => {
      layoutItems.push(item.i);
      if (paramsItems.includes(item.i)) {
        // 对已有的部件修改
        params.configuration.widgets[item.i] = {
          col: item.y,
          row: item.x,
          sizeX: item.w,
          sizeY: item.h,
          type: item.widget.type,
          config: {
            color: JSON.stringify(item.widget.config[item.i].formData),
          },
          typeFullFqn: '',
        };
      } else {
        // 没有的部件进行添加
        params.configuration.widgets[item.i] = {
          col: item.y,
          row: item.x,
          sizeX: item.w,
          sizeY: item.h,
          type: item.widget.type,
          config: {
            color: JSON.stringify(item.widget.config[item.i].formData),
          },
          typeFullFqn: '',
        };
      }
    });
    // 删除不存在的部件
    for (const item in params.configuration.widgets) {
      if (!layoutItems.includes(item)) {
        delete params.configuration.widgets[item];
      }
    }
    nextTick(async () => {
      await addDashboard(params);
      loading.value = false;
      createMessage.success('保存成功');
    });
  };

  // 处理初始多个部件的layout数据
  const initLayout = async (widgets: Recordable) => {
    for (const item in widgets) {
      const { col, row, sizeX, sizeY, type, config } = widgets[item];
      const formData = JSON.parse(config.color);
      const widgetData = await getWidgetData(ws.getAndIncrementCmdId(), type, formData);
      layout.push({
        x: row,
        y: col,
        w: sizeX,
        h: sizeY,
        i: item,
        widget: {
          config: {
            [item]: {
              formData,
              widgetData,
            },
          },
          type: type,
          x: row,
          y: col,
          w: sizeX,
          h: sizeY,
        },
      });
    }
  };

  onMounted(async () => {
    const res = await apiDashboard(route.query.id as string);
    params.id = res.id;
    params.createdTime = res.createdTime;
    params.tenantId = res.tenantId;
    params.title = res.title;
    params.image = res.image;
    params.assignedCustomers = res.assignedCustomers;
    params.mobileHide = res.mobileHide;
    params.mobileOrder = res.mobileOrder;
    if (!res.configuration.hasOwnProperty('widgets')) {
      Object.assign(res.configuration, { widgets: {} });
    }
    params.configuration = res.configuration;
    initLayout(params.configuration.widgets);
  });
</script>

<style lang="less" scoped>
  :deep(.split-pane .left) {
    display: none;
  }

  :deep(.vgl-item .header) {
    display: none;
  }

  :deep(.vgl-item .vue-repl) {
    height: 100% !important;
  }

  :deep(.vgl-item .vue-repl .right, .vgl-item .vue-repl .right .output-container, .vgl-item
      .vue-repl
      .right
      .output-container
      .iframe-container) {
    height: 100% !important;
    width: 100% !important;
  }

  :deep(.vgl-item .vue-repl .right .tab-buttons) {
    display: none;
  }

  :deep(.err) {
    display: none;
  }

  :deep(.vgl-item:not(.vgl-item--placeholder)) {
    background-color: #fff;
  }

  :deep(.vgl-item:active) {
    background-color: #fff;
    border: 1px solid #039be5;
    box-shadow: 0px 0px 20px #039be5;
  }

  :deep(.vgl-item--resizing) {
    opacity: 90%;
  }

  :deep(.vgl-item--static) {
    background-color: #cce;
  }

  .text {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: auto;
    font-size: 24px;
    text-align: center;
  }

  .vgl-layout {
    background-color: #f0f2f5;
  }
</style>
